﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DDD {
    /// <summary>
    /// シェーダーからボーンによる変形に必要なSkinnedMeshクラスの情報に
    /// アクセスするためのマテリアルクラス
    /// </summary>
    public class BoneTransformMaterial : Material {

        #region Field
        SkinnedMesh msh;
        #endregion

        #region Property
        /// <summary>
        /// スキニング行列
        /// </summary>
        /// <remarks>
        /// この行列を頂点座標にかけると変形後の頂点位置が求まります。
        /// 座標系は変形前、変形後ともにローカル座標です。
        /// インデックスにはボーンインデックスを使用します。
        /// </remarks>
        public Matrix4x4[] SkinningMatrices {
            get {
                if (msh == null) {
                    throw new InvalidOperationException ("SkinnedMesh is not set");
                }
                var mat = new Matrix4x4[msh.BoneCount];
                for (var i = 0; i < mat.Length; i++) {
                    mat[i] = msh.GetSkinningMatrix (i);
                }
                return mat;
            }
        }

        /// <summary>
        /// <see cref="SkinningMatrices"/>の法線バージョンです
        /// </summary>
        /// <remarks>
        /// この行列を頂点法線にかけると変形後の法線が求まります。
        /// そのほかの注意事項は<see cref="SkinningMatrices"/>と同じです。
        /// </remarks>
        public Matrix3x3[] NormalSkinningMatrices {
            get {
                if (msh == null) {
                    throw new InvalidOperationException ("SkinnedMesh is not set");
                }
                var mat = new Matrix3x3[msh.BoneCount];
                for (var i = 0; i < mat.Length; i++) {
                    mat[i] = msh.GetNormalSkinningMatrix (i);
                }
                return mat;
            }
        }

        /// <summary>
        /// スキンメッシュコンポーネント
        /// </summary>
        public SkinnedMesh SkinnedMesh {
            get { return msh; }
        }

        /// <summary>
        /// このオブジェクトが参照する全DDDオブジェクトを列挙する列挙子
        /// </summary>
        /// <remarks>
        /// 参照にnullは含まれません。同一のオブジェクトが複数出現する可能性があります。
        /// </remarks>
        public override IEnumerable<Object> References {
            get {
                return base.References;
            }
        }
        #endregion

        #region Constructor
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public BoneTransformMaterial () {
            this.msh = null;
        }
        #endregion

        #region Method
        /// <summary>
        /// スキンメッシュコンポーネントのセット
        /// </summary>
        /// <remarks>
        /// ボーンの変形の元になる<see cref="SkinnedMesh"/>オブジェクトへの参照です。
        /// 必須です。
        /// </remarks>
        /// <param name="msh">スキンメッシュコンポーネント</param>
        public void SetSkinnedMesh (SkinnedMesh msh) {
            this.msh = msh;
        }
        #endregion
    }
}
